package main

import (
	"gitee.com/zy_blue7/zy-go-core/common"
	"github.com/gin-gonic/gin"
	"net/http"
)

type Person struct {
	Name string `form:"name" json:"name"` //`form:"name"` todo 如果是form表单数据，就使用form，postman选中 body-》formdata       如果传的是json数据，就使用json postman选中body-》raw-》json
	Age  int    `form:"age" json:"age"`
	Sex  string `form:"sex" json:"sex"`
}

type Man struct {
	Happy  string `json:"happy"`
	Person Person `json:"person"`
}

func main() {
	jsonServer()
}

func jsonServer() {

	r := gin.Default()

	//----------------todo 返回给前端数据-------------------------------------------------

	r.GET("/json", func(c *gin.Context) {
		//方法1： 使用map
		//data := map[string]interface{}{
		//	"name":"张三",
		//	"age":16,
		//	"sex":"男",
		//}

		//c.JSON(http.StatusOK,data)
		//c.JSON(http.StatusOK,result)
		//fmt.Println(result)
		//fmt.Println(data)
		//c.JSON(http.StatusOK,12)

		//todo 自己拼写json
		c.JSON(http.StatusOK, gin.H{"name": "张三"})

	})

	r.GET("json-struct", func(c *gin.Context) {
		//todo 方法2： 结构体
		person := Person{
			Name: "张三",
			Age:  16,
			Sex:  "男",
		}

		result := common.Result{
			Result:  person,
			Code:    "200",
			Message: "success",
		}

		c.JSON(http.StatusOK, result)
	})

	//---------------------todo 从url获取请求参数  ?name=zhangs&age=19 --------------------------------------------------------------

	r.GET("query-url", func(c *gin.Context) {

		//query := c.Query("query")

		//todo 娶不到值就使用默认的值
		//query := c.DefaultQuery("query", "default")

		//todo 返回两个参数，第二个参数表示 是否取到数据， true 表示取到数据，false则取不到数据
		query, ok := c.GetQuery("query")
		if !ok {
			query = "nidaye"
		}

		c.JSON(http.StatusOK, gin.H{"name": query})
	})

	//---------------------------todo form表单参数--------------------------------------------------------------------------------

	r.POST("post", func(c *gin.Context) {

		//获取name参数, 通过PostForm获取的参数值是String类型。
		name := c.PostForm("name")

		// 跟PostForm的区别是可以通过第二个参数设置参数默认值
		//name := c.DefaultPostForm("name", "sockstack")

		//获取id参数, 通过GetPostForm获取的参数值也是String类型,
		// 区别是GetPostForm返回两个参数，第一个是参数值，第二个参数是参数是否存在的bool值，可以用来判断参数是否存在。
		//id, ok := c.GetPostForm("id")
		//if !ok {
		//	// 参数不存在
		//}
		c.JSON(http.StatusOK, gin.H{"name": name})
	})

	//-----------------------------todo 获取url 路径参数   /user/id -------------------------------------------------------------------------

	r.GET("user/:id/:age", func(c *gin.Context) {
		id := c.Param("id")

		age := c.Param("age")
		c.JSON(http.StatusOK, gin.H{"name": id, "age": age})
	})

	//----------------------------todo 通过结构体接受请求体--------------------------------------------------------------------------------------------------------

	r.POST("query-struct", func(c *gin.Context) {

		var person Person //声明一个person的结构体变量

		err := c.ShouldBind(&person) //todo 必须传入 地址，因为如果传入的是person， 只是将传值， 在函数里面修改的person的值，并不会影响到函数外面
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
		} else {
			c.JSON(http.StatusOK, person)
		}

	})

	r.POST("query-struct-man", func(c *gin.Context) {

		var man Man //声明一个person的结构体变量

		//todo 测试结构体嵌套结构体
		err := c.ShouldBind(&man) //todo 必须传入 地址，因为如果传入的是person， 只是将传值， 在函数里面修改的person的值，并不会影响到函数外面

		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
		} else {
			c.JSON(http.StatusOK, man)
		}

	})

	//todo 经过测试表明，get请求传入请求体是不会被映射到 结构体中的
	r.GET("query-struct-get", func(c *gin.Context) {

		var man Man //声明一个person的结构体变量

		//todo 测试结构体嵌套结构体
		err := c.ShouldBind(&man) //todo 必须传入 地址，因为如果传入的是person， 只是将传值， 在函数里面修改的person的值，并不会影响到函数外面

		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
		} else {
			c.JSON(http.StatusOK, man)
		}

		/**
		todo 响应体，可以看到，get请求请求参数并没有被映射到结构体中
		{
		    "happy": "",
		    "person": {
		        "name": "",
		        "age": 0,
		        "sex": ""
		    }
		}

		*/
	})

	//---------------------------------------todo 上传文件 ---------------------------------------------------------------------------------
	r.POST("upload", func(c *gin.Context) {

		//	从请求中读取文件
		file, err := c.FormFile("file")

		//todo 多文件上传
		//form, err := c.MultipartForm()

		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
		} else {
			_ = c.SaveUploadedFile(file, "a.bmp")
		}

		//	将读取到的文件保存到服务端

	})

	//------------------------------todo 重定向----------------------------------------------------------------------
	r.GET("test", func(c *gin.Context) {

		c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com")

		//c.JSON(http.StatusOK, gin.H{"message": "ok"})

	})

	//-----------------------------todo  没有路由的东东---------------------------------------------------
	r.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"message": "没有这个地址，别访问了"})
	})

	//--------------------------todo 路由组---------------------------------------
	userGroup := r.Group("/user")
	{

		userGroup.GET("/get", func(c *gin.Context) {

		})
		userGroup.POST("/update", func(c *gin.Context) {

		})
		userGroup.PUT("insert", func(c *gin.Context) {

		})
		userGroup.DELETE("delete", func(c *gin.Context) {

		})

		//todo 路由组支持嵌套
		addressGroup := userGroup.Group("/address")

		{
			addressGroup.GET("/select", func(c *gin.Context) {

			})
		}
	}

	r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

// 默认的请求
func serverDefault() {
	r := gin.Default() //返回默认的路由引擎
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
